package com.ruoyi.wetest.stats;

import com.codahale.metrics.Histogram;
import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer;

import java.util.List;

/**
 * @author luch
 */
public class MessageSnapshot {
    private final long startTime;
    private final long endTime;
    private final List<CodeStatSnapshot> codeStatSnapshots;

    public MessageSnapshot(long startTime,
                           long endTime,
                           List<CodeStatSnapshot> codeStatSnapshots) {
        this.startTime = startTime;
        this.endTime = endTime;
        this.codeStatSnapshots = codeStatSnapshots;
    }

    public long getStartTime() {
        return startTime;
    }

    public long getEndTime() {
        return endTime;
    }

    public List<CodeStatSnapshot> getCodeStatSnapshots() {
        return codeStatSnapshots;
    }

    /**
     * @author luch
     */
    public static final class CodeStatSnapshot {
        /**
         * 序号
         */
        final Integer number;
        /**
         * 事务名称
         */
        final String transName;

        /**
         * rx <-> tx packs tps and latency
         */
        final TimerSnapshot rxtx;
        final OneWaySnapshot oneWayRx;

        public CodeStatSnapshot(String transName,
                                Integer number, TimerSnapshot rxtx,
                                OneWaySnapshot oneWayRx) {
            this.transName = transName;
            this.rxtx = rxtx;
            this.oneWayRx = oneWayRx;
            this.number = number;
        }

    }

    /**
     * 单向消息
     */
    public static final class OneWaySnapshot {
        final long packs;
        /**
         * 成功个数
         */
        final long succ;
        /**
         * 失败个数
         */
        final long fail;

        /**
         * 错误个数
         */
        final long error;

        /**
         * 超时个数
         */
        final long timeout;

        /**
         * 成功率
         */
        final double succRate;

        public OneWaySnapshot(CodeStat.OneWayStat oneWay) {
            this.packs = oneWay.getPacks().getCount();
            this.succ = oneWay.getSucc().getCount();
            this.fail = oneWay.getFail().getCount();
            this.error = oneWay.getError().getCount();
            this.timeout = oneWay.getTimeout().getCount();
            this.succRate = oneWay.getSuccRate();
        }
    }

    public static class MetricSnapshot {
        final Double min;
        final Double max;
        final Double mean;
        final Double p50;
        final Double p75;
        final Double p90;
        final Double p95;
        final Double p99;
        final Double p999;


        public MetricSnapshot(double min, double max, double mean, double p50, double p75, double p90, double p95, double p99, double p999) {
            this.min = min;
            this.max = max;
            this.mean = mean;
            this.p50 = p50;
            this.p75 = p75;
            this.p90 = p90;
            this.p95 = p95;
            this.p99 = p99;
            this.p999 = p999;
        }

    }

    public static final class HistogramSnapshot extends MetricSnapshot {
        final long count;

        public HistogramSnapshot(Histogram histogram) {
            this(histogram.getSnapshot(),
                    histogram.getCount(), 1);
        }

        public HistogramSnapshot(Snapshot ss, long count, double durationFactor) {
            super(convertDuration(ss.getMin(), durationFactor),
                    convertDuration(ss.getMax(), durationFactor),
                    convertDuration(ss.getMean(), durationFactor),
                    convertDuration(ss.getMedian(), durationFactor),
                    convertDuration(ss.get75thPercentile(), durationFactor),
                    convertDuration(ss.getValue(0.9), durationFactor),
                    convertDuration(ss.getValue(0.95), durationFactor),
                    convertDuration(ss.get99thPercentile(), durationFactor),
                    convertDuration(ss.get999thPercentile(), durationFactor));
            this.count = count;
        }

        public static String getHistogramSnapshotByStr(Snapshot ss, double durationFactor) {
            return convertDuration(ss.getMax(), durationFactor).intValue() + "|" +
                    convertDuration(ss.getMin(), durationFactor).intValue() + "|" +
                    convertDuration(ss.getMean(), durationFactor).intValue() + "|" +
                    convertDuration(ss.getMedian(), durationFactor).intValue() + "|" +
                    convertDuration(ss.getValue(0.9), durationFactor).intValue() + "|";
        }

    }

    public static final class TimerSnapshot {
        /**
         * count
         */
        final long count;
        final double meanRate;
        final double oneMinuteRate;
        final double fiveMinuteRate;
        final double fifteenMinuteRate;
        final HistogramSnapshot histogramSnapshot;

        public TimerSnapshot(Timer timer, double rateFactor, double durationFactor) {
            this.count = timer.getCount();
            this.meanRate = convertRate(timer.getMeanRate(), rateFactor);
            this.oneMinuteRate = convertRate(timer.getOneMinuteRate(), rateFactor);
            this.fiveMinuteRate = convertRate(timer.getFiveMinuteRate(), rateFactor);
            this.fifteenMinuteRate = convertRate(timer.getFifteenMinuteRate(), rateFactor);
            this.histogramSnapshot = new HistogramSnapshot(timer.getSnapshot(), timer.getCount(), durationFactor);
        }

    }

    public static Double convertDuration(double duration, double durationFactor) {
        return duration;
        // return duration / durationFactor;
    }

    public static Double convertRate(double rate, double rateFactor) {
        return rate * rateFactor;
    }

}
